package com.example.userserver.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.result.R;
import com.example.common.util.JWTUtil;
import com.example.userserver.entity.User;
import com.example.userserver.mapper.UserMapper;
import com.example.userserver.service.IUserService;
import com.example.userserver.vo.UserVO;
import io.netty.util.internal.StringUtil;

import java.util.Collections;

import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author benjamin_5
 * @Description
 * @date 2023/2/22
 */
@Service
@AllArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final RedisTemplate redisTemplate;
    private final UserMapper userMapper;

    @Override
    public R getToken(String userName, String password) {
        User user = getCacheByUserName(userName);
        if (user == null) {
            return R.fail("账号不存在");
        }
        if (!password.equals(user.getPassword())) {
            return R.fail("密码错误");
        }
        // 思考：这里为什么要加前缀
        String key = "token:" + userName;
        String token = (String) redisTemplate.opsForValue().get(key);
        // 思考：这里为什么要判断token是否过期
        if (!StringUtil.isNullOrEmpty(token) && !JWTUtil.isExpiration(token)) {
            return R.data(token);
        }
        // 生成token
        token = JWTUtil.generateToken(userName);
        // 存放缓存并设置过期时间
        redisTemplate.opsForValue().set(key, token);
        redisTemplate.expire(key, 1L, TimeUnit.HOURS);
        return R.data(token);
    }

    @Override
    public User getCacheByUserName(String userName) {
        User user = (User) redisTemplate.opsForValue().get(userName);
        if (user != null) {
            return user;
        }
        User one = this.getOne(Wrappers.<User>lambdaQuery().eq(User::getUserName, userName));
        redisTemplate.opsForValue().set(userName, one);
        return one;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R save(UserVO userVO) {
        User user = new User();
        // 拷贝属性
        BeanUtils.copyProperties(userVO, user);
        Object execute = redisTemplate.execute(new SessionCallback<List<Boolean>>() {
            @Override
            @Transactional(rollbackFor = Exception.class)
            public List<Boolean> execute(RedisOperations operations) throws DataAccessException {
                operations.multi();
                operations.opsForValue().set(user.getUserName(), user);
                try {
                    saveUser(user);
                    if (999 == user.getAge()) {
                        int i = 1 / 0;
                    }
                } catch (Exception e) {
                    operations.discard();
                    e.printStackTrace();
                    return null;
                }
                return operations.exec();
            }
        });
        System.out.println("返回结果：" + JSON.toJSONString(execute));
//        int i = 1/0;
        return R.status(execute != null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R save2(UserVO userVO) {
        User user = new User();
        // 拷贝属性
        BeanUtils.copyProperties(userVO, user);
        try {
            // 设置缓存
            redisTemplate.opsForValue().set(user.getUserName(), user);
            // 保存数据库
            saveUser(user);
            if (999 == user.getAge()) {
                int i = 1 / 0;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("操作失败");
        }
        return R.success("操作成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R save3(UserVO userVO) {
        User user = new User();
        // 拷贝属性
        BeanUtils.copyProperties(userVO, user);
        try {
            // 保存数据库
            saveUser(user);
            int i = 1 / 0;
        } catch (Exception e) {
            // 手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            e.printStackTrace();
            return R.fail("操作失败");
        }
        return R.success("操作成功");
    }

    private void saveUser(User user) throws Exception {
        if (user.getId() != null) {
            userMapper.updateUser(user);
        } else {
            int id = userMapper.selectCount(Wrappers.lambdaQuery()) + 1;
            while (userMapper.selectById(id) != null) {
                id++;
            }
            user.setId((long) id);
            userMapper.addUser(user);
        }
    }
}
